package com.sxfans.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Socket报文常用通讯工具
 * 
 * @author Li-Wen.Zhang
 * 
 */
public class SocketClientUtils {
	private static Log log = LogFactory.getLog(SocketClientUtils.class);

	/**
	 * 建立socket连接
	 * @param hostname - 主机名
	 * @param port - 端口
	 * @param so_timeout - 读数据超时时间（百万分之一秒），milseconds
	 * @return
	 * @throws UnknownHostException
	 * @throws IOException
	 * @throws SocketException
	 */
	public static Socket open(String hostname, int port, int so_timeout)
			throws UnknownHostException, IOException, SocketException {
		Socket sc = null;
		try {
			sc = new Socket(hostname, port);
			sc.setSoTimeout(so_timeout);
		} catch (UnknownHostException e) {
			log.error("无效的主机名 '" + hostname + "', " + e.getMessage());
			throw e;
		} catch (IOException e) {
			log.error("连接服务器 '" + hostname + ":" + port + "' 失败, "+ e.getMessage());
			throw e;
		}

		log.info("connect ok, " + sc);
		return sc;
	}

	/**
	 * 发送数据
	 * @param sc - socket套接字
	 * @param data - 数据
	 * @throws IOException
	 */
	public static void send(Socket sc, byte[] data) throws IOException {
		OutputStream out = sc.getOutputStream();
		out.write(data);
		out.flush();
	}

	/**
	 * 从socket接收数据
	 * @param sc - 套接字
	 * @param len - 接收数据长度
	 * @return
	 * @throws IOException
	 */
	public static byte[] receive(Socket sc, final int len) throws IOException {
		return receive(sc.getInputStream(),len);
	}

	/**
	 * 从数据流中读取指定长度的数据
	 * @param in - 输入流
	 * @param len - 需要读取的数据长度
	 * @return 读取到的固定长度数据
	 * @throws IOException  超时、输入流被关闭、...
	 */
	public static byte[] receive(InputStream in, final int len)
			throws IOException {
		byte buf[] = new byte[len];

		int i;
		int offset = 0;

		while (offset < len) {
			i = in.read(buf, offset, len - offset);
			if (i > 0) {
				offset += len;
			} else if (i == 0) {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					log.info("wait InterruptedException", e);
				}
			} else {
				if (offset > 0) {
					log.info("socket fail, read return -1, read data="
							+ new String(buf, 0, offset));
				}
				throw new IOException("socket fail, read return -1");
			}
		}

		return buf;
	}
	
	/**
	 * @param sc
	 * @return
	 * @throws IOException
	 */
	public static byte[] receive(Socket sc) throws IOException {
		InputStream in = sc.getInputStream();
		FilterInputStream bf = new BufferedInputStream(in);
		int rs = -1;
		List<Byte> list = new ArrayList<Byte>();
		while ((rs = bf.read()) != -1) {
			list.add((byte)rs);
		}
		byte[] by = new byte[list.size()];
		for (int i = 0; i < by.length; i++) {
			by[i] = list.get(i);
		}
		return by;
	}

	/**
	 * 关闭socket连接
	 * 
	 * @param socket
	 *            - 套接字
	 */
	public static void close(Socket socket) {
		if (socket != null) {
			try {
				socket.close();
			} catch (Exception e) {
				log.error("关闭socket失败， " + e.getMessage(), e);
			}
		}
	}

	public static void main(String args[]) {
		Socket sc = null;
		int len = 5000000;
		if (args.length == 1) {
			len = Integer.parseInt(args[0]);
		}

		// String str = "123|456|789";
		// String s[] = str.split("\\|");
		// log.info("s.length=" + s.length);
		// for (int i=0; i<s.length; i++)
		// log.info("s[" + i + "]=" + s[i]);

		try {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < 50000000; i++) {
				sb.append((char) (0x30 + i % 9));
			}
			System.out.println("string len=" + sb.toString().length());
		} catch (Exception e) {
			log.warn("Exception" + e.getMessage(), e);
		}

		try {
			sc = open("qa.yeepay.com", 80, 5000);

			ByteBuffer bb = ByteBuffer.allocate(50000);
			bb.put("GET /individualservice/Login.action?".getBytes());
			for (int i = 0; i < 48000; i++) {
				bb.put((byte) (48 + i % 9));
			}
			bb.put(" HTTP/1.0\n\r\n\r".getBytes());

			bb.rewind();
			byte buf[] = new byte[50000];
			bb.get(buf);
			send(sc, buf);

			 send(sc, "GET / HTTP/1.0\n\r\n\r".getBytes());
			byte[] data = receive(sc, 100);
			System.out.println("receive data: \n" + new String(data, "GBK"));
		} catch (IOException e) {
			;
		} finally {
			close(sc);
		}

	}
}
